﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using LeafTransmission.Entity;
using LeafTransmission.Entity.ConfigEntity;

namespace LeafTransmission.Utils
{
    internal class XMLDocumentUtil
    {
        // 默认配置文件的存储路径
        public const string CONFIG_PATH = "Config";
        public const string USER_INFO_CONFIG_XML = "UserInfoConfig.xml";
        public const string NETWORK_CONFIG_XML = "NetworkConfig.xml";
        public const string FILE_DIRECTORY_CONFIG_XML = "FileDirectoryConfig.xml";

        // 配置文件的element
        private static readonly XElement _userInfoXMLRoot;
        private static readonly XElement _fileDirectoryXMLRoot;
        private static readonly XElement _networkXMLRoot;

        static XMLDocumentUtil()
        {
            // 配置文件初始化
            // 
            CreateAllDefaultConfigXML(false);

            string currentDirectory = Directory.GetCurrentDirectory();
            // 在类加载时,加载配置文件
            _userInfoXMLRoot = XElement.Load(FileUtil.ContactFilePath(USER_INFO_CONFIG_XML, currentDirectory, CONFIG_PATH));
            _fileDirectoryXMLRoot = XElement.Load(FileUtil.ContactFilePath(FILE_DIRECTORY_CONFIG_XML, currentDirectory, CONFIG_PATH));
            _networkXMLRoot = XElement.Load(FileUtil.ContactFilePath(NETWORK_CONFIG_XML, currentDirectory, CONFIG_PATH));
        }

        // 批量修改节点的值

        // 单个修改节点的值

        /// <summary>
        /// 通过节点的name修改单个节点的值, 并且该节点为根节点(没有子节点)
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="nodeName"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool UpdateRootNodeValueByName(string filename, string nodeName, string value)
        {
            XElement docTree = ActionXMLFile(filename);
            try
            {
                XElement node = docTree.Element(nodeName);
                node.Value = value;
                string path = FileUtil.ContactFilePath(filename, Directory.GetCurrentDirectory(), CONFIG_PATH);
                docTree.Save(path);
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        // 单层子节点值的修改(对应用户配置文件的 WorkGroups 或 网卡配置文件中的网段信息)
        public static bool UpdateSingleTierNodeValueByValue(string filename, string nodeValue,string parentNodeName, string value)
        {
            XElement docTree = ActionXMLFile(filename);
            try
            {
                // 父节点
                XElement parentNode = docTree.Element(parentNodeName);
                // 查询父节点下的所有子节点
                IEnumerable<XElement> subList =
                    from el in parentNode.Descendants()
                    where el.Value == nodeValue
                    select el;
                foreach (var item in subList)
                {
                    item.Value = value;
                }


                string path = FileUtil.ContactFilePath(filename, Directory.GetCurrentDirectory(), CONFIG_PATH);
                docTree.Save(path);
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// 修改两层子节点的Attribute属性值,通过父节点与子节点的属性值共同确定
        /// 对应用户配置文件的工作组
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="parentNodeName"></param>
        /// <param name="attributeName"></param>
        /// <param name="targetNodeValue"></param>
        /// <param name="attributeValue"></param>
        /// <returns></returns>
        public static bool UpdateSingleTierNodeAttributeByParentNodeName(string filename, string parentNodeName, string attributeName,string targetNodeValue, string attributeValue)
        {
            XElement docTree = ActionXMLFile(filename);
            try
            {
                // 父节点
                XElement parentNode = docTree.Element(parentNodeName);

                // 查询所有子节点, 单层
                IEnumerable<XElement> segments =
                    from el in parentNode.Descendants()
                    select el;
                foreach (var item in segments)
                {
                    if (bool.Parse(item.Attribute(attributeName).Value))
                    {
                        item.Attribute(attributeName).Value = "False";
                    }

                    if (item.Value.ToString() == targetNodeValue)
                    {
                        item.Attribute(attributeName).Value = "True";
                    }
                }
                string path = FileUtil.ContactFilePath(filename, Directory.GetCurrentDirectory(), CONFIG_PATH);
                docTree.Save(path);
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// 修改多层节点的 Attribute 属性值,通过节点值与节点名(该值必须唯一)
        /// 目前版本该方法只对应网络配置文件的网卡选中属性的修改, 三层节点的属性值修改.
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="nodeValue"></param>
        /// <param name="parentNodeName"></param>
        /// <param name="attributeValue"></param>
        /// <returns></returns>
        public static bool UpdateMultilayerNodeAttributeByNode(string filename, string nodeName, string nodeValue, string parentNodeName, string attributeValue)
        {
            XElement docTree = ActionXMLFile(filename);
            try
            {
                // 网卡信息
                XElement nicsEle = docTree.Element(parentNodeName);
                // 查询每个网卡信息
                var allNIC =
                    from ele in nicsEle.Elements()
                    group ele by ele into newGroup
                    select newGroup;

                // 1. 先将原先节点的选中属性设为 False
                foreach (var item in allNIC)// 所有NICS下的NIC分组
                {
                    foreach (var sub in item)// NIC
                    {
                        sub.Attribute("selected").Value = "False";
                    }
                }

                // 2. 在将目标节点的属性设置True
                foreach (var item in allNIC)// 所有NICS下的NIC分组
                {
                    foreach (var sub in item)// NIC
                    {
                        var tmp =
                            from ele in sub.Elements()
                            select ele;
                        foreach (var sub2 in tmp)// NIC 中的每个属性
                        {
                            if (sub2.Value == nodeValue)
                            {
                                sub.Attribute("selected").Value = "True";
                            }
                        }

                    }
                }
                string path = FileUtil.ContactFilePath(filename, Directory.GetCurrentDirectory(), CONFIG_PATH);
                docTree.Save(path);
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        private static XElement ActionXMLFile(string filename)
        {
            switch (filename)
            {
                case USER_INFO_CONFIG_XML:
                     return _userInfoXMLRoot;
                case NETWORK_CONFIG_XML:
                    return _networkXMLRoot;
                case FILE_DIRECTORY_CONFIG_XML:
                    return _fileDirectoryXMLRoot;
                default:
                    return null;
            }
        }



        /*
         * 改变网卡: 改变网卡的attribute selected 属性值
         * 通过where value = targetValue 找到 修改其selected值为true
         * 更改原来选中的网卡selected = false
         * 
         */
        /*
         * 改变网段
         * 1. 添加: 添加节点
         * 2. 删除: 删除节点
         * 3. 修改: 修改网段的Attribute selected 属性值
         */

        public static UserInfoConfigEntity GetUserInfoConfigXML()
        {
            UserInfoConfigEntity result = new UserInfoConfigEntity();
            XElement emailEle = _userInfoXMLRoot.Element("Email");
            // 获取Email节点之前的所有数据
            IEnumerable<XElement> afterEmailElements = emailEle.ElementsBeforeSelf();
            foreach (XElement item in afterEmailElements)
            {
                if (item.Name.ToString() == "Avatar")
                {
                    result.Avatar = item.Value;
                }
                if (item.Name.ToString() == "Username")
                {
                    result.Username = item.Value;
                }
            }
            result.Email = emailEle.Value;


            // 所有工作组
            XElement workgroupsElement = _userInfoXMLRoot.Element("Workgroups");
            // 查询每个工作组
            IEnumerable<XElement> workgroups =
                from el in workgroupsElement.Descendants()
                select el;
            foreach (var item in workgroups)
            {
                Workgroup workgroup = new Workgroup();  
                workgroup.Name = item.Value.ToString();
                workgroup.Selected = bool.Parse(item.Attribute("selected").Value);
                result.workgroups.Add(workgroup);
            }


            return result;
        }

        public static FileDirectoryConfigEntity GetFileDirectoryConfigXML()
        {
            FileDirectoryConfigEntity result = new FileDirectoryConfigEntity();
            IEnumerable<XElement> nodes =
                   from ele in _fileDirectoryXMLRoot.Descendants()
                   select ele;

            foreach (var node in nodes)
            {
                if (node.Name.ToString() == "FileSavedDirectory")
                {
                    result.FileSavedDirectory = node.Value;
                }
                if (node.Name.ToString() == "FileCacheDirectory")
                { 
                    result.FileCacheDirectory = node.Value;
                }
            }

            return result;
        }


        #region 获取网卡信息相关操作
        public static NetworkConfigEntity GetNetworkConfigXML()
        {
            NetworkConfigEntity result = new NetworkConfigEntity();
            /*
             * 获取前三个数据
             * <UDPPort>8899</UDPPort>
             * <TCPServerPort>9988</TCPServerPort>
             * <TCPRemotePort>9989</TCPRemotePort>
             */
            XElement tcpRemotePortEle = _networkXMLRoot.Element("TCPRemotePort");
            // 获取TCPRemotePort节点之前的所有数据
            IEnumerable<XElement> afterTcpRemotePortElements = tcpRemotePortEle.ElementsBeforeSelf();
            foreach (XElement item in afterTcpRemotePortElements)
            {
                if (item.Name.ToString() == "UDPPort")
                { 
                    result.UDPPort = Convert.ToInt32(item.Value);
                }
                if (item.Name.ToString() == "TCPServerPort")
                {
                    result.TCPServerPort = Convert.ToInt32(item.Value);
                }
            }
            result.TCPRemotePort = Convert.ToInt32(tcpRemotePortEle.Value);


            // 网卡信息
            XElement nicsEle = _networkXMLRoot.Element("NICS");
            // 查询每个网卡信息
            var allNIC =
                from ele in nicsEle.Elements()
                group ele by ele into newGroup
                select newGroup;
            foreach (var item in allNIC)
            {
                // Console.WriteLine(item.ToString());
                foreach (var sub in item)
                {
                    NICEntity nicEntity = new NICEntity();
                    var tmp =
                        from ele in sub.Elements()
                        select ele;

                    nicEntity.Selected = bool.Parse(sub.Attribute("selected").Value);
                    foreach (var sub2 in tmp)
                    {
                        switch (sub2.Name.ToString())
                        {
                            case "Id":
                                nicEntity.Id = sub2.Value;
                                break;
                            case "OperationalStatus":
                                nicEntity.OperationalStatus = sub2.Value;
                                break;
                            case "Name":
                                nicEntity.Name = sub2.Value;
                                break;
                            case "IPv4Address":
                                nicEntity.IPv4Address = sub2.Value;
                                break;
                            case "IPv4Mask":
                                nicEntity.IPv4Mask = sub2.Value;
                                break;
                            case "Description":
                                nicEntity.Description = sub2.Value;
                                break;
                            case "PhysicalAddress":
                                nicEntity.PhysicalAddress = sub2.Value;
                                break;
                        }
                    }
                    result.NICEntities.Add(nicEntity);
                }
            }

            // 网段信息
            XElement networkSegments = _networkXMLRoot.Element("NetworkSegments");
            // 查询所有网段信息
            IEnumerable<XElement> segments =
                from el in networkSegments.Descendants()
                select el;
            foreach (var item in segments)
            {
                NetworkSegmentEntity networkSegmentEntity = new NetworkSegmentEntity();
                networkSegmentEntity.Segment = item.Value;
                networkSegmentEntity.Selected = bool.Parse(item.Attribute("selected").Value);
                result.NetworkSegmentEntities.Add(networkSegmentEntity);
            }
           
            return result;
        }
        
        #endregion

        /// <summary>
        /// 创建所有默认配置文件
        /// </summary>
        /// <param name="createForce">是否强制覆盖创建</param>
        /// <returns></returns>
        public static bool CreateAllDefaultConfigXML(bool createForce)
        {
            return CreateDefaultUserInfoXML(createForce) &
                CreateDefaultNetworkConfigXML(createForce) &
                CreateDefaultFileDirectoryConfigXML(createForce);
        }


        /// <summary>
        /// 创建默认文件路径配置文件,
        /// </summary>
        /// <param name="createForce">是否强制创建 true 强制 false 若不存在创建</param>
        /// <returns>
        /// 当createForce为true强制时, 返回是否创建成功
        /// 当CreateForce为false时, 若文件存在则返回false ,若文件不存在返回是否创建成功
        /// </returns>
        public static bool CreateDefaultFileDirectoryConfigXML(bool createForce)
        {
            if (createForce)
            {
                return CreateDefaultFileDirectoryConfigXML(FILE_DIRECTORY_CONFIG_XML, CONFIG_PATH);
            }
            else
            {
                var result = FileUtil.JudgeFileExistsInCurrentDirectory(FILE_DIRECTORY_CONFIG_XML, CONFIG_PATH);
                if (FileUtil.VALUE_FALSE.Equals(result[FileUtil.KEY_EXISTS]))
                {
                    return CreateDefaultFileDirectoryConfigXML(FILE_DIRECTORY_CONFIG_XML, CONFIG_PATH);
                }
                return false;
            }
        }

        /// <summary>
        /// 创建默认用户配置文件,
        /// </summary>
        /// <param name="createForce">是否强制创建 true 强制 false 若不存在创建</param>
        /// <returns>
        /// 当createForce为true强制时, 返回是否创建成功
        /// 当CreateForce为false时, 若文件存在则返回false ,若文件不存在返回是否创建成功
        /// </returns>
        public static bool CreateDefaultUserInfoXML(bool createForce)
        {
            if (createForce)
            {
                return CreateDefaultUserInfoXML(USER_INFO_CONFIG_XML, CONFIG_PATH);
            }
            else
            {
                var result = FileUtil.JudgeFileExistsInCurrentDirectory(USER_INFO_CONFIG_XML, CONFIG_PATH);
                if (FileUtil.VALUE_FALSE.Equals(result[FileUtil.KEY_EXISTS]))
                {
                    return CreateDefaultUserInfoXML(USER_INFO_CONFIG_XML, CONFIG_PATH);
                }
                return false;
            }
        }

        /// <summary>
        /// 创建默认网络配置文件,
        /// </summary>
        /// <param name="createForce">是否强制创建 true 强制 false 若不存在创建</param>
        /// <returns>
        /// 当createForce为true强制时, 返回是否创建成功
        /// 当CreateForce为false时, 若文件存在则返回false ,若文件不存在返回是否创建成功
        /// </returns>
        public static bool CreateDefaultNetworkConfigXML(bool createForce)
        {
            if (createForce)
            {
                return CreateDefaultNetworkConfigXML(NETWORK_CONFIG_XML, CONFIG_PATH);
            }
            else
            {
                var result = FileUtil.JudgeFileExistsInCurrentDirectory(NETWORK_CONFIG_XML,CONFIG_PATH);
                if (FileUtil.VALUE_FALSE.Equals(result[FileUtil.KEY_EXISTS]))
                {
                    return CreateDefaultNetworkConfigXML(NETWORK_CONFIG_XML, CONFIG_PATH);
                }
                return false;
            }
            
        }

        /// <summary>
        /// 创建默认用户信息xml文件
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="relativePath"></param>
        /// <returns>
        ///     若存在不创建返回 false
        ///     若不存在则创建,并返回 true
        /// </returns>
        public static bool CreateDefaultUserInfoXML(string filename, params string[] relativePath)
        {
            XDocument docTree = new XDocument(
                    new XDeclaration("1.0", "UTF-8", null),//（版本,编码,独立属性）
                    new XElement("Root",
                        new XElement("Avatar", "null"),
                        new XElement("Username", "主机名/用户名"),
                        new XElement("Email", "66688889999@163.com"),
                        new XElement("Workgroups", 
                            new XElement("Workgroup", new XAttribute("selected", "True"), "defaultWorkgroup"),
                            new XElement("Workgroup", new XAttribute("selected", "False"), "otherGroup")
                            )
                        )
                );

            // Console.WriteLine(docTree.ToString());

            var result = FileUtil.CreateDirectoryInPWDIfNotExists(relativePath);
            string fullPath = FileUtil.ContactFilePath(filename, result[FileUtil.KEY_PATH]);

            docTree.Save(fullPath);
            return true;

        }

        /// <summary>
        /// 创建默认文件存储路径配置xml文件
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="relativePath"></param>
        /// <returns>
        ///     若存在不创建返回 false
        ///     若不存在则创建,并返回 true
        /// </returns>
        public static bool CreateDefaultFileDirectoryConfigXML(string filename, params string[] relativePath)
        {
            /*
            <?xml version="1.0" encoding="utf-8" ?>
            <Root>
	            <FileSavedDirectory>D:\LeafDownload</FileSavedDirectory>
	            <FileCacheDirectory>D:\LeafDownload\Cache</FileCacheDirectory>
            </Root>
             */
            XDocument docTree = new XDocument(
                    new XDeclaration("1.0", "UTF-8", null),//（版本,编码,独立属性）
                    new XElement("Root",
                        new XElement("FileSavedDirectory", @"D:\LeafDownload"),
                        new XElement("FileCacheDirectory", @"D:\LeafDownload\Cache")
                        )
                );
            // Console.WriteLine(docTree.ToString());
            var result = FileUtil.CreateDirectoryInPWDIfNotExists(relativePath);

            string fullPath = FileUtil.ContactFilePath(filename, result[FileUtil.KEY_PATH]);

            docTree.Save(fullPath);
            return true;
        }

        /// <summary>
        /// 创建默认网卡配置xml文件
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="relativePath"></param>
        /// <returns>
        ///     若存在不创建返回 false
        ///     若不存在则创建,并返回 true
        /// </returns>
        public static bool CreateDefaultNetworkConfigXML(string filename, params string[] relativePath)
        {
            NetworkConfigEntity networkConfigEntity = new NetworkConfigEntity();
            networkConfigEntity.UDPPort = 8899;
            networkConfigEntity.TCPServerPort = 9988;
            networkConfigEntity.TCPRemotePort = 9989;

            // ipv4列表的添加
            List<NICEntity> nicEntities = NICUtil.GetAllNICSInfo();
            // MessageBox.Show(nicEntities[0].IPv4Address);
            foreach (NICEntity item in nicEntities)// ip地址的有效性过滤
            {
                if (item.IPv4Address == "" || item.IPv4Address.Length < 0)
                {
                    nicEntities.Remove(item);
                }
            }

            // 默认最后一个网卡选中
            nicEntities[nicEntities.Count - 1].Selected = true;

            networkConfigEntity.NICEntities = nicEntities;

            var ipv4AddrList = networkConfigEntity.GetAllIPv4Address();
            // 默认选中最后一个网段,目前网段的选中没有作用
            networkConfigEntity.NetworkSegmentEntities =
                NICUtil.GetAllSegment(ipv4AddrList, ipv4AddrList.Count - 1);


            XElement root = new XElement("Root");
            root.Add(new XElement("UDPPort", networkConfigEntity.UDPPort));
            root.Add(new XElement("TCPServerPort", networkConfigEntity.TCPServerPort));
            root.Add(new XElement("TCPRemotePort", networkConfigEntity.TCPRemotePort));
            XElement nics = new XElement("NICS");
            foreach (var item in networkConfigEntity.NICEntities)
            {
                XElement nic = new XElement("NIC");
                if (item.Selected)
                {
                    nic.SetAttributeValue("selected", "True");
                }
                else
                {
                    nic.SetAttributeValue("selected", "False");
                }


                nic.Add(new XElement("Id", item.Id));
                nic.Add(new XElement("OperationalStatus", item.OperationalStatus));
                nic.Add(new XElement("Name", item.Name));
                nic.Add(new XElement("IPv4Address", item.IPv4Address));
                nic.Add(new XElement("IPv4Mask", item.IPv4Mask));
                nic.Add(new XElement("Description", item.Description));
                nic.Add(new XElement("PhysicalAddress", item.PhysicalAddress));

                nics.Add(nic);
            }
            root.Add(nics);
            XElement segments = new XElement("NetworkSegments");
            foreach (var item in networkConfigEntity.NetworkSegmentEntities)
            {
                XElement segment = new XElement("Segment");
                if (item.Selected == true)
                {
                    segment.SetAttributeValue("selected", "True");
                }
                else
                {
                    segment.SetAttributeValue("selected", "False");
                }
                segment.Value = item.Segment;

                segments.Add(segment);
            }
            root.Add(segments);
            XDocument docTree = new XDocument(new XDeclaration("1.0", "UTF-8", null));
            docTree.Add(root);


            /*XDocument docTree = new XDocument(
                    new XDeclaration("1.0", "UTF-8", null),//（版本,编码,独立属性）
                    new XElement("Root",
                        new XElement("UDPPort", "8899"),// UDP服务端口
                        new XElement("TCPServerPort", "9988"),// TCP 服务端口
                        new XElement("TCPRemotePort", "9989"),// TCP 远端端口
                        new XElement("NICS", 
                            new XElement("NIC", new XAttribute("selected", "False"),
                                new XElement("Id", "{2BDD053B-D34B-4B87-BF09-5BE0FE7433ED}"),
                                new XElement("OperationalStatus","Down"),
                                new XElement("Name", "以太网"),
                                new XElement("IPv4Address", "192.168.10.100"),
                                new XElement("IPv4Mask", "255.255.255.0"),
                                new XElement("Description", "VMware Virtual Ethernet Adapter for VMnet"),
                                new XElement("PhysicalAddress", "00-50-56-C0-00-00")
                            ), 
                            new XElement("NIC", new XAttribute("selected", "True"),
                                new XElement("Id", "{2BDD053B-D34B-4B87-BF09-5BE0FE7433ED}"),
                                new XElement("OperationalStatus", "Up"),
                                new XElement("Name", "WLAN"),
                                new XElement("IPv4Address", "172.16.20.100"),
                                new XElement("IPv4Mask", "255.255.255.0"),
                                new XElement("Description", "Intel(R) Wireless-AC 9462"),
                                new XElement("PhysicalAddress", "50-E0-85-E2-90-64")
                            ),
                            new XElement("NIC", new XAttribute("selected", "False"),
                                new XElement("Id", "{2BDD053B-D34B-4B87-BF09-5BE0FE7433ED}"),
                                new XElement("OperationalStatus", "Up"),
                                new XElement("Name", "以太网"),
                                new XElement("IPv4Address", "192.168.20.100"),
                                new XElement("IPv4Mask", "255.255.255.0"),
                                new XElement("Description", "VMware Virtual Ethernet Adapter for VMnet0"),
                                new XElement("PhysicalAddress", "00-50-56-C0-00-00")
                            )
                        ),
                        new XElement("NetworkSegments",// 所有网段
                            new XElement("Segment", new XAttribute("selected", "False"), "192.168.10.0"),
                            new XElement("Segment", new XAttribute("selected", "True"), "172.16.20.0"),
                            new XElement("Segment", new XAttribute("selected", "False"), "192.168.30.0")
                        )

                    )
                );*/
            // Console.WriteLine(docTree.ToString());

            var result = FileUtil.CreateDirectoryInPWDIfNotExists(relativePath);
            string fullPath = FileUtil.ContactFilePath(filename, result[FileUtil.KEY_PATH]);
            docTree.Save(fullPath);
            return true;

        }

        
    }
}
